package cc.cc4414.cc02.core.webSocket;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;

import cc.cc4414.cc02.core.constant.RedisConsts;
import cc.cc4414.cc02.core.result.ResultEnum;
import cc.cc4414.cc02.core.result.ResultException;
import cc.cc4414.cc02.system.entity.User;
import lombok.extern.slf4j.Slf4j;

/**
 * @author cc 2018年10月6日
 */
@Component
@ServerEndpoint(value = "/webSocket/{token}", configurator = WebSocketConfigurator.class)
@Slf4j
@Scope("prototype")
// TODO 下个版本优化这个类
public class WebSocket {

	@Autowired
	private TokenStore tokenStore;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	private Session session;

	private Long userId;

	private static Map<Long, WebSocket> map = new ConcurrentHashMap<Long, WebSocket>();

	@OnOpen
	public void onOpen(Session session, @PathParam("token") String token) {
		User user = new User();
		OAuth2Authentication authentication = tokenStore.readAuthentication(token);
		if (authentication == null) {
			log.warn("用户未登陆");
			return;
		}
		UserDetails userDetails = (UserDetails) authentication.getPrincipal();
		BeanUtils.copyProperties(userDetails, user);
		this.session = session;
		this.userId = user.getId();
		map.put(user.getId(), this);
		stringRedisTemplate.opsForValue().set(RedisConsts.ONLINE + user.getId(), "1", 1, TimeUnit.DAYS);
		log.info("【websocket消息】有新的连接, 用户id:{}", this.userId);
	}

	@OnClose
	public void onClose() {
		if (this.userId != null) {
			map.remove(this.userId);
			stringRedisTemplate.delete(RedisConsts.ONLINE + this.userId);
			log.info("【websocket消息】连接断开, 用户id:{}", this.userId);
		}
	}

	public void sendMessage(String message, Long userId) {
		WebSocket webSocket = map.get(userId);
		if (webSocket == null) {
			log.error("发送消息失败", new ResultException(ResultEnum.OTHER_NOT_CONNECT));
			return;
		}
		try {
			webSocket.session.getBasicRemote().sendText(message);
		} catch (IOException e) {
			log.error("发送消息失败", e);
		}
	}

}
